// --- Copyright (c) 2010 Steven Hartgers ---
// Copyright (C) 2010 Steven Hartgers All rights are reserved.
// Author contact: fiinix00/at\gmail.com
// ------------------------------------------------------------------------
// This program is free software: you can redistribute it and/or modify 
// it under the terms of the GNU General Public License as published by 
// the Free Software Foundation, either version 3 of the License, or 
// (at your option) any later version. 
//  
// This program is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
// GNU General Public License for more detail
//  
// You should have received a copy of the GNU General Public License 
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
// ------------------------------------------------------------------------
// COPYRIGHT NOTICE: This copyright notice may NOT be removed, obscured or modified 
// without written consent from the author.
// --- End copyright notice --- 



using System;
using System.IO;
using System.Net.Sockets;

namespace Hack.Net.Smtp
{
    /** Create sending object of a mail */
    public class SmtpSending
    {
        /** My host name  */
        private readonly string myhost;

        /** The sender address */
        private readonly string mailfrom;

        /** Parameters of MAIL FROM: */
        private readonly string mailfromparams;

        /** The receiver address */
        private readonly string rcpto;

        /** Parameters of RCPT TO: */
        private readonly string rcptoparams;

        /** The data section */
        private readonly string data;



        /** Create a sending object of SMTP */
        public SmtpSending(string myhost, string mailfrom, string mailfromparams,
                        string rcpto, string rcptoparams, string data)
        {
            this.myhost = myhost;
            this.mailfrom = mailfrom;
            this.mailfromparams = mailfromparams;
            this.rcpto = rcpto;
            this.rcptoparams = rcptoparams;
            this.data = data;
        }

        /** Create a sending object of SMTP */
        public SmtpSending(string myhost, string mailfrom, string rcpto, string data) :
            this(myhost, mailfrom, null, rcpto, null, data)
        {
        }



        /** Send mail to host */
        public bool Send(string host, int port)
        {
            //Connect to host
            TcpClient client = new TcpClient(host, port);

            //Create reader/writer
            Stream stream = client.GetStream();
            StreamReader reader = new StreamReader(stream);
            StreamWriter writer = new StreamWriter(stream);


            //Read greeting from server
            reader.ReadLine();

            if (!ProcessEhlo(reader, writer))
                return false;

            if (!ProcessMailFrom(reader, writer))
                return false;

            if (!ProcessRcpTo(reader, writer))
                return false;

            if (!ProcessData(reader, writer))
                return false;

            return ProcessQuit(reader, writer);
        }

        /** Send a message */
        private void SendMessage(StreamWriter writer, string msg)
        {
            writer.Write(msg + "\r\n");
            writer.Flush();
        }

        /** Check for answer with status 250 */
        private bool CheckAnswer(StreamReader reader, StreamWriter writer, string begins)
        {
            string answer = reader.ReadLine();

            //Something went wrong
            if (!answer.StartsWith(begins))
            {
                SendMessage(writer, "QUIT");
                return false;
            }

            return true;
        }

        /** Return true if everything ok, otherwise false */
        private bool ProcessQuit(StreamReader reader, StreamWriter writer)
        {
            SendMessage(writer, "QUIT");
            return CheckAnswer(reader, writer, "221");
        }

        /** Return true if everything ok, otherwise false */
        private bool ProcessEhlo(StreamReader reader, StreamWriter writer)
        {
            //Send ehlo message...
            SendMessage(writer, "EHLO " + myhost);

            return CheckAnswer(reader, writer, "250");
        }

        /** Return true if everything ok, otherwise false */
        private bool ProcessMailFrom(StreamReader reader, StreamWriter writer)
        {
            //Build sending string
            string msg = "MAIL FROM:<" + mailfrom + ">";

            //Append params, if existing
            if (mailfromparams != null && mailfromparams.Length > 0)
                msg += " <" + mailfromparams + ">";


            SendMessage(writer, msg);

            return CheckAnswer(reader, writer, "250");
        }

        /** Return true if everything ok, otherwise false */
        private bool ProcessRcpTo(StreamReader reader, StreamWriter writer)
        {
            //Build sending string
            string msg = "RCPT TO:<" + rcpto + ">";

            //Append params, if existing
            if (rcptoparams != null && rcptoparams.Length > 0)
                msg += " <" + rcptoparams + ">";


            SendMessage(writer, msg);

            return CheckAnswer(reader, writer, "250");
        }

        /** Return true if everything ok, otherwise false */
        private bool ProcessData(StreamReader reader, StreamWriter writer)
        {

            //Send DATA command
            SendMessage(writer, "DATA");

            if (!CheckAnswer(reader, writer, "350"))
                return false;

            //Send data itself
            SendMessage(writer, data + "\r\n.");

            return CheckAnswer(reader, writer, "250");
        }
    }

}